//============================================================================
// Name        : TetragnathaBeta.cpp
// Author      : MC e Baggio
// Version     :
// Copyright   : 
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <fstream>
#include <queue>
#include <list>
#include <sstream>

#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <boost/tr1/memory.hpp>

#include <curl/curl.h>
#include <curl/types.h>
#include <curl/easy.h>

#include <ctime>
#include <cstdlib>

#include "./classes_net/DownloadParser.h"
#include "./classes_net/URL.h"
#include "./classes_dados/ManagerBerthier.h"
#include "./classes_dados/ThreadFunctionDatabase.h"


#include "./classes_dados/URLDiskClass.h"
#include "./classes_outros/Config.h"
#include "./classes_outros/MCSugaException.h"
#include "./classes_outros/TetraRecovery.h"

using namespace std;


void initList(list<URL> &urlList){
	URL tempUrl;
	tempUrl = URL("www.globo.com/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.terra.com/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.terra.com.br/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.uol.com.br/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.ita.br/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.ufmg.br/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.aol.com/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.yahoo.com.br/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.cnn.com/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.bbc.co.uk/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.centraldoslinks.com/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.sites.jpa.com.br/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.guialinks.com.br/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.nytimes.com/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.planetasites.com/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.abril.com.br/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.sitesnobrasil.com/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.mapadaweb.com.br/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.top30.com.br/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.mundosites.net/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.ig.com.br/", "", "http://");
	urlList.push_back(tempUrl);
	
}



int main(int argc, char *argv[]) {
	
	curl_global_init(CURL_GLOBAL_ALL);
	
	pthread_attr_t attr;
	size_t stacksize;
	uint numDownloaderThreads = Config::getNumDownloaderThreads();
	uint numQueueThreads = Config::getNumQueueThreads();
	
	pthread_t threads[numDownloaderThreads];
	pthread_t queueThread[numQueueThreads];
	pthread_t robotThreads[100];
	
	list<URL> urlList;
	DownloadParser downloadTeste;
	
	std::tr1::shared_ptr<URLFileDealer> urlFileDealer = URLFileDealer::getInstance();
	std::tr1::shared_ptr<ManagerBerthier> mb = ManagerBerthier::getInstance();
	
	
	
//	int totalThread =0;
	int rc;	
	unsigned int t = 0; //kker valor - MC Suga, caguei
	
	TetraRecovery backup;
	
	bool inicializaFrio = true;
	
	if (Config::redirectCOutToFile())
		freopen ("myfile.txt","w",stdout);	
	
	if(argc < 2){
		cout << " Verifique argumentos... " << endl;
		exit(1);
	}
	
	switch(*argv[1]){
		case '0':
	//		if (Config::runInitializationScript())
			system("./setup.sh");
			break;
		case '1':
			
			cout << "Inicializando Threads getDomainRobots()..." << endl;
			pthread_attr_init(&attr);
			stacksize = Config::getRobotsThreadStackSize();
			pthread_attr_setstacksize (&attr, stacksize);
			for(t=0; t<100; t++){ 
				rc = pthread_create(&robotThreads[t], &attr, ThreadFunctionDatabase::getDomainRobots, (void *)t); 
				if (rc){
				  cout << "ThreadFunctionDatabase erro na Recuperacao: " << rc << "\n";
				  exit(-1);
				}
			}			
			
			//Recupera apos quebra
			backup.recovery();
			cout << "------------------------------------------------------------------------------" << endl;
			cout << "------------------------------------------------------------------------------" << endl;
			cout << "      Tetragnatha Recuperado " << endl;
			cout << "------------------------------------------------------------------------------" << endl;
			cout << "------------------------------------------------------------------------------" << endl;
			inicializaFrio = false;
//			return 0;
			break;
			
		case '2':
			//Recupera apos quebra
			cout << "Modo especial: " << endl;
			cout << "Gerando estatisticas: backup.currentState() " << endl;
			time_t tempo;
			time(&tempo);
			freopen ("./out_logger/niveis","a",stdout);
			while(true) backup.currentState(tempo);  // fica gerando estatistica
			return 0;
			break;
			
		case '3':
			cout << "------------------------------------------------------------------------------" << endl;
			cout << "------------------------------------------------------------------------------" << endl;
			backup.contaPaginasDisco();
			cout << "------------------------------------------------------------------------------" << endl;
			cout << "------------------------------------------------------------------------------" << endl;
			return 0;
			break;
			
		default:
			cout << " Verifique argumentos... " << endl;	
			exit(1);
	}
	
	//	std::tr1::shared_ptr<ManagerBerthier> mb = ManagerBerthier::getInstance();
	//	mb->testPriorityQueue();
	//	return 0;
	
	
	cout << "blah" << endl; 
	
	if(inicializaFrio){
		//Carrega lista de URLs
		initList(urlList);
		
		int numUrlsNaMain = 0;
		list<URL>::iterator it;
		
		for(it = urlList.begin(); it != urlList.end(); it++){
			list<URL> urlListTemp;
			downloadTeste.setURL(it->toString());
			urlListTemp = downloadTeste.getNewURLs();
			urlFileDealer->addURLs(urlListTemp);
			numUrlsNaMain += urlListTemp.size();
			cout << "Size: " << urlListTemp.size() << endl;
			cout << "urlFileDealer->addURLs(urlListTemp) na main() "<< endl;
			cout << "Total parcial:P: " << numUrlsNaMain << endl;
		}		
	}

	
	cout << "-----------------------------------------------------------" << endl;
	cout << "-----------------------------------------------------------" << endl;
	cout << "-----------------------------------------------------------" << endl;
	cout << "-----------------------------------------------------------" << endl;
	cout << "-----------------------------------------------------------" << endl;
	cout << "-----------------------------------------------------------" << endl;
	cout << "-----------------------------------------------------------" << endl;
	cout << "-----------------------------------------------------------" << endl;
	cout << "-----------------------------------------------------------" << endl;
	
//	return 0;
	
//	tempUrl = mb->getNewURL();	
//	string temp_ = tempUrl.get_protocol() + tempUrl.get_dominio() + tempUrl.get_path();
//	downloadTeste.setURL(temp_);
//	urlList = downloadTeste.getNewURLs();
//	urlFileDealer->addURLs(urlList);
	
	
//	for(int i=0; i<1; i++){  // i < 3
//	
//		tempUrl = mb->getNewURL();
//		while( tempUrl.isValid() ){
//			string temp_ = tempUrl.get_protocol() + tempUrl.get_dominio() + tempUrl.get_path();
//			downloadTeste.setURL(temp_);
//			urlList = downloadTeste.getNewURLs();
//			for(it = urlList.begin(); it != urlList.end(); it++) 	urlFileDealer->addToDiskBuffer(*it);
//			tempUrl = mb->getNewURL();
//		}
//	
//		//imprime lista
//		cout << endl << endl;
//		for(it = urlList.begin(); it != urlList.end(); it++)
//			cout << it->get_protocol() << it->get_dominio() << it->get_path() << endl;
//
//	}
	
	
//	cout << "Testa interface com arquivos" << endl;
//	char * bufferList = new char[ 100*sizeof(list<int>)/sizeof(char)]; 
//	list<int> *listaInt = new(bufferList) list<int>;
//	delete [] bufferList;
//
//	Disk disco;
//	
//	disco.writeDisk(10);
//	disco.writeDisk(11);
//	disco.writeDisk(12);
//	
//	cout << "Gravado:  " << disco.readDisk() << endl;
//	cout << "Gravado:  " << disco.readDisk() << endl;
//	cout << "Gravado:  " << disco.readDisk() << endl;
	

	mb->initializeDownloaderQueues(numDownloaderThreads);

	if(inicializaFrio){
		   
		pthread_attr_init(&attr);
		stacksize = Config::getRobotsThreadStackSize();
		pthread_attr_setstacksize (&attr, stacksize);
		for(t=0; t<100; t++){ 
			rc = pthread_create(&robotThreads[t], &attr, ThreadFunctionDatabase::getDomainRobots, (void *)t); 
			if (rc){
			  cout << "MB::findURL - ERROR1; return ROBOTS code from pthread_create() is " << rc << "\n";
			  exit(-1);
			}
		}	
		
	}
	
	pthread_attr_init(&attr);
	stacksize = Config::getQueueThreadStackSize();
	pthread_attr_setstacksize (&attr, stacksize);
	   
	//REENCHEDOR DE FILAS
    for(t=0; t<numQueueThreads; t++){ 
    	//rc = pthread_create(&queueThread[t], NULL, ThreadFunctionDatabase::manageDownloaderQueues, (void *)t);
    	rc = pthread_create(&queueThread[t], &attr, ThreadFunctionDatabase::manageDownloaderQueues, (void *)t); 
    	if (rc){
    	  cout << "ERROR1; return code from pthread_create() is " << rc << "\n";
    	  exit(-1);
      }
   }
    
    
    pthread_attr_init(&attr);
    stacksize = Config::getDownloaderThreadStackSize();
    pthread_attr_setstacksize (&attr, stacksize);
    
    //Funcionarios do ManagerBerthier
	   for(t=0; t<numDownloaderThreads; t++){ 
	      rc = pthread_create(&threads[t], &attr, ThreadFunctionDatabase::downloadInit, (void *)t);
	      //rc = pthread_create(&threads[t], NULL, ThreadFunctionDatabase::downloadInit, (void *)t);
	      if (rc){
	    	  cout << "ERROR2; return code from pthread_create() is " << rc << "\n";
	    	  exit(-1);
	      }
	   }
	   printf("Created %d threads.\n", t);
	   pthread_exit(NULL);
			
//	boost::thread_group threads;
//	for (int i = 0; i < 400; ++i) threads.create_thread(&ThreadFunctionDatabase::downloadInit);
//	try{
//		threads.join_all();
//	}
//	catch(...) {
//		cout << "MC causou erro na main" << endl;
//	}
	
	curl_global_cleanup();
	return 0;
	
}


